home *** CD-ROM | disk | FTP | other *** search
- /* Output sdb-format symbol table information from GNU compiler.
- Copyright (C) 1988 Free Software Foundation, Inc.
-
- This file is part of GNU CC.
-
- GNU CC is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 1, or (at your option)
- any later version.
-
- GNU CC is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
- #include "config.h"
-
- #ifdef SDB_DEBUGGING_INFO
-
- #include "tree.h"
- #include "rtl.h"
- #include <stdio.h>
- #include <syms.h>
- /* #include <storclass.h> used to be this instead of syms.h. */
-
- /* Line number of beginning of current function, minus one. */
-
- int sdb_begin_function_line = 0;
-
- /* Counter to generate unique "names" for nameless struct members. */
-
- static int unnamed_struct_number = 0;
-
- extern FILE *asm_out_file;
-
- extern tree current_function_decl;
-
- void sdbout_init ();
- void sdbout_symbol ();
- void sdbout_tags();
- void sdbout_types();
-
- static void sdbout_syms ();
- static void sdbout_one_type ();
- static int plain_type_1 ();
-
- /* Random macros describing parts of SDB data. */
-
- /* Put something here if lines get too long */
- #define CONTIN
-
- #ifndef PUT_SDB_SCL
- #define PUT_SDB_SCL(a) fprintf(asm_out_file, "\t.scl\t%d;", (a))
- #endif
-
- #ifndef PUT_SDB_INT_VAL
- #define PUT_SDB_INT_VAL(a) fprintf (asm_out_file, "\t.val\t%d;", (a))
- #endif
-
- #ifndef PUT_SDB_VAL
- #define PUT_SDB_VAL(a) \
- ( fputs ("\t.val\t", asm_out_file), \
- output_addr_const (asm_out_file, (a)), \
- fputc (';', asm_out_file))
- #endif
-
- #ifndef PUT_SDB_DEF
- #define PUT_SDB_DEF(a) \
- do { fprintf (asm_out_file, "\t.def\t"); \
- ASM_OUTPUT_LABELREF (asm_out_file, a); \
- fprintf (asm_out_file, ";"); } while (0)
- #endif
-
- #ifndef PUT_SDB_PLAIN_DEF
- #define PUT_SDB_PLAIN_DEF(a) fprintf(asm_out_file,"\t.def\t.%s;",a)
- #endif
-
- #ifndef PUT_SDB_ENDEF
- #define PUT_SDB_ENDEF fputs("\t.endef\n", asm_out_file)
- #endif
-
- #ifndef PUT_SDB_TYPE
- #define PUT_SDB_TYPE(a) fprintf(asm_out_file, "\t.type\t0%o;", a)
- #endif
-
- #ifndef PUT_SDB_SIZE
- #define PUT_SDB_SIZE(a) fprintf(asm_out_file, "\t.size\t%d;", a)
- #endif
-
- #ifndef PUT_SDB_DIM
- #define PUT_SDB_DIM(a) fprintf(asm_out_file, "\t.dim\t%d;", a)
- #endif
-
- #ifndef PUT_SDB_TAG
- #define PUT_SDB_TAG(a) \
- do { fprintf (asm_out_file, "\t.tag\t"); \
- ASM_OUTPUT_LABELREF (asm_out_file, a); \
- fprintf (asm_out_file, ";"); } while (0)
- #endif
-
- #ifndef PUT_SDB_BLOCK_START
- #define PUT_SDB_BLOCK_START(LINE) \
- fprintf (asm_out_file, \
- "\t.def\t.bb;\t.val\t.;\t.scl\t100;\t.line\t%d;\t.endef\n", \
- (LINE))
- #endif
-
- #ifndef PUT_SDB_BLOCK_END
- #define PUT_SDB_BLOCK_END(LINE) \
- fprintf (asm_out_file, \
- "\t.def\t.eb;.val\t.;\t.scl\t100;\t.line\t%d;\t.endef\n", \
- (LINE))
- #endif
-
- #ifndef PUT_SDB_FUNCTION_START
- #define PUT_SDB_FUNCTION_START(LINE) \
- fprintf (asm_out_file, \
- "\t.def\t.bf;\t.val\t.;\t.scl\t101;\t.line\t%d;\t.endef\n", \
- (LINE))
- #endif
-
- #ifndef PUT_SDB_FUNCTION_END
- #define PUT_SDB_FUNCTION_END(LINE) \
- fprintf (asm_out_file, \
- "\t.def\t.ef;\t.val\t.;\t.scl\t101;\t.line\t%d;\t.endef\n", \
- (LINE))
- #endif
-
- #ifndef PUT_SDB_EPILOGUE_END
- #define PUT_SDB_EPILOGUE_END(NAME) \
- fprintf (asm_out_file, \
- "\t.def\t%s;\t.val\t.;\t.scl\t-1;\t.endef\n", \
- (NAME))
- #endif
-
- #ifndef SDB_GENERATE_FAKE
- #define SDB_GENERATE_FAKE(BUFFER, NUMBER) \
- sprintf ((BUFFER), ".%dfake", (NUMBER));
- #endif
-
- /* Return the sdb tag identifier string for TYPE
- if TYPE has already been defined; otherwise return a null pointer. */
-
- #define KNOWN_TYPE_TAG(type) (char *)(TYPE_SYMTAB_ADDRESS (type))
-
- /* Set the sdb tag identifier string for TYPE to NAME. */
-
- #define SET_KNOWN_TYPE_TAG(TYPE, NAME) \
- (TYPE_SYMTAB_ADDRESS (TYPE) = (int)(NAME))
-
- /* Return the name (a string) of the struct, union or enum tag
- described by the TREE_LIST node LINK. This is 0 for an anonymous one. */
-
- #define TAG_NAME(link) \
- (((link) && TREE_PURPOSE ((link)) \
- && IDENTIFIER_POINTER (TREE_PURPOSE ((link)))) \
- ? IDENTIFIER_POINTER (TREE_PURPOSE ((link))) : (char *) 0)
-
- /* Ensure we don't output a negative line number. */
- #define MAKE_LINE_SAFE(line) \
- if (line <= sdb_begin_function_line) line = sdb_begin_function_line + 1
-
- /* Tell the assembler the source file name.
- On systems that use SDB, this is done whether or not -g,
- so it is called by ASM_FILE_START.
-
- ASM_FILE is the assembler code output file,
- INPUT_NAME is the name of the main input file. */
-
- void
- sdbout_filename (asm_file, input_name)
- FILE *asm_file;
- char *input_name;
- {
- int len = strlen (input_name);
- char *na = input_name + len;
-
- /* NA gets INPUT_NAME sans directory names. */
- while (na > input_name)
- {
- if (na[-1] == '/')
- break;
- na--;
- }
-
- #ifdef ASM_OUTPUT_SOURCE_FILENAME
- ASM_OUTPUT_SOURCE_FILENAME (asm_file, na);
- #else
- fprintf (asm_file, "\t.file\t\"%s\"\n", na);
- #endif
- }
-
- /* Set up for SDB output at the start of compilation. */
-
- void
- sdbout_init ()
- {
- /* Output all the initial permanent types. */
- sdbout_types (nreverse (get_permanent_types ()));
- }
-
- #if 0
-
- /* return the tag identifier for type
- */
-
- {
- char *
- tag_of_ru_type (type,link)
- tree type,link;
- {
- if (TYPE_SYMTAB_ADDRESS (type))
- return (char *)TYPE_SYMTAB_ADDRESS (type);
- if (link &&
- TREE_PURPOSE (link)
- && IDENTIFIER_POINTER (TREE_PURPOSE (link)))
- TYPE_SYMTAB_ADDRESS (type) =
- (int)IDENTIFIER_POINTER (TREE_PURPOSE (link));
- else
- return (char *) TYPE_SYMTAB_ADDRESS (type);
- }
- #endif
-
- /* Return a unique string to name an anonymous type. */
-
- static char *
- gen_fake_label ()
- {
- char label[10];
- char *labelstr;
- SDB_GENERATE_FAKE (label, unnamed_struct_number);
- unnamed_struct_number++;
- labelstr = (char *) permalloc (strlen (label) + 1);
- strcpy (labelstr, label);
- return labelstr;
- }
-
- /* Return the number which describes TYPE for SDB.
- For pointers, etc., this function is recursive.
- Each record, union or enumeral type must already have had a
- tag number output. */
-
- /* The number is given by d6d5d4d3d2d1bbbb
- where bbbb is 4 bit basic type, and di indicate one of notype,ptr,fn,array.
- Thus, char *foo () has bbbb=T_CHAR
- d1=D_FCN
- d2=D_PTR
- N_BTMASK= 017 1111 basic type field.
- N_TSHIFT= 2 derived type shift
- N_BTSHFT= 4 Basic type shift */
-
- /* Produce the number that describes a pointer, function or array type.
- PREV is the number describing the target, value or element type.
- DT_type describes how to transform that type. */
- #define PUSH_DERIVED_LEVEL(DT_type,PREV) \
- ((((PREV)&~N_BTMASK)<<N_TSHIFT)|(DT_type<<N_BTSHFT)|(PREV&N_BTMASK))
-
- static int
- plain_type (type)
- tree type;
- {
- int val = plain_type_1 (type);
- if (TREE_CODE (type) == ARRAY_TYPE)
- {
- int size = int_size_in_bytes (type);
- /* Don't kill sdb if type is not laid out or has variable size. */
- if (size < 0)
- size = 0;
- PUT_SDB_SIZE (size);
- }
- return val;
- }
-
- static void
- sdbout_record_type_name (type)
- tree type;
- {
- char *name = 0;
-
- if (KNOWN_TYPE_TAG (type))
- return;
-
- if (TYPE_NAME (type) != 0)
- {
- tree t = 0;
- /* Find the IDENTIFIER_NODE for the type name. */
- if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
- {
- t = TYPE_NAME (type);
- }
- else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL)
- {
- t = DECL_NAME (TYPE_NAME (type));
- }
-
- /* Now get the name as a string, or invent one. */
- if (t != 0)
- name = IDENTIFIER_POINTER (t);
- }
-
- if (name == 0)
- name = gen_fake_label ();
-
- SET_KNOWN_TYPE_TAG (type, name);
- }
-
- static int
- plain_type_1 (type)
- tree type;
- {
- if (type == 0)
- type = void_type_node;
- if (type == error_mark_node)
- type = integer_type_node;
- type = TYPE_MAIN_VARIANT (type);
-
- switch (TREE_CODE (type))
- {
- case VOID_TYPE:
- return T_INT;
- case INTEGER_TYPE:
- switch (int_size_in_bytes (type))
- {
- case 4:
- return (TREE_UNSIGNED (type) ? T_UINT : T_INT);
- case 1:
- return (TREE_UNSIGNED (type) ? T_UCHAR : T_CHAR);
- case 2:
- return (TREE_UNSIGNED (type) ? T_USHORT : T_SHORT);
- default:
- return 0;
- }
- case REAL_TYPE:
- switch (int_size_in_bytes (type))
- {
- case 4:
- return T_FLOAT;
- default:
- return T_DOUBLE;
- }
- case ARRAY_TYPE:
- {
- int m = plain_type (TREE_TYPE (type));
- PUT_SDB_DIM (TYPE_DOMAIN (type)
- ? TREE_INT_CST_LOW (TYPE_MAX_VALUE (TYPE_DOMAIN (type))) + 1
- : 0);
- return PUSH_DERIVED_LEVEL (DT_ARY, m);
- }
- case RECORD_TYPE:
- case UNION_TYPE:
- case ENUMERAL_TYPE:
- {
- char *tag;
- int size;
- sdbout_record_type_name (type);
- if (TREE_ASM_WRITTEN (type))
- {
- /* Output the referenced structure tag name
- only if the .def has already been output.
- At least on 386, the Unix assembler
- cannot handle forward references to tags. */
- tag = KNOWN_TYPE_TAG (type);
- PUT_SDB_TAG (tag);
- }
- size = int_size_in_bytes (type);
- if (size < 0)
- size = 0;
- PUT_SDB_SIZE (size);
- return ((TREE_CODE (type) == RECORD_TYPE) ? T_STRUCT
- : (TREE_CODE (type) == UNION_TYPE) ? T_UNION
- : T_ENUM);
- }
- case POINTER_TYPE:
- case REFERENCE_TYPE:
- {
- int m = plain_type (TREE_TYPE (type));
- return PUSH_DERIVED_LEVEL (DT_PTR, m);
- }
- case FUNCTION_TYPE:
- case METHOD_TYPE:
- {
- int m = plain_type (TREE_TYPE (type));
- return PUSH_DERIVED_LEVEL (DT_FCN, m);
- }
- default:
- return 0;
- }
- }
-
- /* Output the symbols defined in block number DO_BLOCK.
- Set NEXT_BLOCK_NUMBER to 0 before calling.
-
- This function works by walking the tree structure,
- counting blocks, until it finds the desired block. */
-
- static int do_block = 0;
-
- static int next_block_number;
-
- static void
- sdbout_block (stmt)
- register tree stmt;
- {
- while (stmt)
- {
- switch (TREE_CODE (stmt))
- {
- case COMPOUND_STMT:
- case LOOP_STMT:
- sdbout_block (STMT_BODY (stmt));
- break;
-
- case IF_STMT:
- sdbout_block (STMT_THEN (stmt));
- sdbout_block (STMT_ELSE (stmt));
- break;
-
- case LET_STMT:
- /* Ignore LET_STMTs for blocks never really used to make RTL. */
- if (! TREE_USED (stmt))
- break;
- /* When we reach the specified block, output its symbols. */
- if (next_block_number == do_block)
- {
- sdbout_tags (STMT_TYPE_TAGS (stmt));
- sdbout_syms (STMT_VARS (stmt));
- }
-
- /* If we are past the specified block, stop the scan. */
- if (next_block_number > do_block)
- return;
-
- next_block_number++;
-
- /* Scan the blocks within this block. */
- sdbout_block (STMT_SUBBLOCKS (stmt));
- }
- stmt = TREE_CHAIN (stmt);
- }
- }
-
- /* Call sdbout_symbol on each decl in the chain SYMS. */
-
- static void
- sdbout_syms (syms)
- tree syms;
- {
- while (syms)
- {
- sdbout_symbol (syms, 1);
- syms = TREE_CHAIN (syms);
- }
- }
-
- /* Output SDB information for a symbol described by DECL.
- LOCAL is nonzero if the symbol is not file-scope. */
-
- void
- sdbout_symbol (decl, local)
- tree decl;
- int local;
- {
- int letter = 0;
- tree type = TREE_TYPE (decl);
-
- /* If global, first output all types and all
- struct, enum and union tags that have been created
- and not yet output. */
-
- if (local == 0)
- {
- sdbout_tags (gettags ());
- sdbout_types (nreverse (get_permanent_types ()));
- }
-
- switch (TREE_CODE (decl))
- {
- case CONST_DECL:
- /* Enum values are defined by defining the enum type. */
- return;
-
- case FUNCTION_DECL:
- if (TREE_EXTERNAL (decl))
- return;
- if (GET_CODE (DECL_RTL (decl)) != MEM
- || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF)
- return;
- PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (decl)));
- PUT_SDB_VAL (XEXP (DECL_RTL (decl), 0));
- PUT_SDB_SCL (TREE_PUBLIC (decl) ? C_EXT : C_STAT);
- break;
-
- case TYPE_DECL:
- /* Output typedef name. */
- PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (decl)));
- PUT_SDB_SCL (C_TPDEF);
- break;
-
- case PARM_DECL:
- /* Parm decls go in their own separate chains
- and are output by sdbout_reg_parms and sdbout_parms. */
- abort ();
-
- case VAR_DECL:
- /* Don't mention a variable that is external.
- Let the file that defines it describe it. */
- if (TREE_EXTERNAL (decl))
- return;
-
- /* Don't mention a variable at all
- if it was completely optimized into nothingness. */
- if (GET_CODE (DECL_RTL (decl)) == REG
- && (REGNO (DECL_RTL (decl)) < 0
- || REGNO (DECL_RTL (decl)) >= FIRST_PSEUDO_REGISTER))
- return;
-
- /* Ok, start a symtab entry and output the variable name. */
- PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (decl)));
-
- if (GET_CODE (DECL_RTL (decl)) == MEM
- && GET_CODE (XEXP (DECL_RTL (decl), 0)) == SYMBOL_REF)
- {
- if (TREE_PUBLIC (decl))
- {
- PUT_SDB_VAL (XEXP (DECL_RTL (decl), 0));
- PUT_SDB_SCL (C_EXT);
- }
- else
- {
- PUT_SDB_VAL (XEXP (DECL_RTL (decl), 0));
- PUT_SDB_SCL (C_STAT);
- }
- }
- else if (GET_CODE (DECL_RTL (decl)) == REG)
- {
- PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (DECL_RTL (decl))));
- PUT_SDB_SCL (C_REG);
- }
- else if (GET_CODE (DECL_RTL (decl)) == MEM
- && (GET_CODE (XEXP (DECL_RTL (decl), 0)) == MEM
- || (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG
- && REGNO (XEXP (DECL_RTL (decl), 0)) != FRAME_POINTER_REGNUM)))
- /* If the value is indirect by memory or by a register
- that isn't the frame pointer
- then it means the object is variable-sized and address through
- that register or stack slot. DBX has no way to represent this
- so all we can do is output the variable as a pointer. */
- {
- if (GET_CODE (XEXP (DECL_RTL (decl), 0)) == REG)
- {
- PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (DECL_RTL (decl))));
- PUT_SDB_SCL (C_REG);
- }
- else
- {
- /* DECL_RTL looks like (MEM (MEM (PLUS (REG...)
- (CONST_INT...)))).
- We want the value of that CONST_INT. */
- /* Encore compiler hates a newline in a macro arg, it seems. */
- PUT_SDB_INT_VAL (INTVAL (XEXP (XEXP (XEXP (DECL_RTL (decl), 0), 0), 1)));
- PUT_SDB_SCL (C_AUTO);
- }
-
- type = build_pointer_type (TREE_TYPE (decl));
- }
- else if (GET_CODE (DECL_RTL (decl)) == MEM
- && GET_CODE (XEXP (DECL_RTL (decl), 0)) == PLUS
- && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 0)) == REG
- && GET_CODE (XEXP (XEXP (DECL_RTL (decl), 0), 1)) == CONST_INT)
- {
- /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...))).
- We want the value of that CONST_INT. */
- PUT_SDB_INT_VAL (INTVAL (XEXP (XEXP (DECL_RTL (decl), 0), 1)));
- PUT_SDB_SCL (C_AUTO);
- }
- else
- {
- /* It is something we don't know how to represent for SDB. */
- }
- break;
- }
- PUT_SDB_TYPE (plain_type (type));
- PUT_SDB_ENDEF;
- }
-
- /* Given a list of TREE_LIST nodes that point at types,
- output those types for SDB.
- We must check to include those that have been mentioned already with
- only a cross-reference. */
-
- void
- sdbout_tags (tags)
- tree tags;
- {
- register tree link;
-
- for (link = tags; link; link = TREE_CHAIN (link))
- {
- register tree type = TREE_VALUE (link);
-
- if (TREE_PURPOSE (link) != 0
- && TYPE_SIZE (type) != 0)
- sdbout_one_type (type);
- }
- }
-
- /* Given a chain of ..._TYPE nodes, all of which have names,
- output definitions of those names, as typedefs. */
-
- void
- sdbout_types (types)
- register tree types;
- {
- register tree link;
-
- for (link = types; link; link = TREE_CHAIN (link))
- sdbout_one_type (link);
- }
-
- static void
- sdbout_type (type)
- tree type;
- {
- register tree tem;
- if (type == error_mark_node)
- type = integer_type_node;
- PUT_SDB_TYPE (plain_type (type));
- }
-
- /* Output types of the fields of type TYPE, if they are structs.
- Don't chase through pointer types, since that could be circular.
- They must come before TYPE, since forward refs are not allowed.
-
- This is not actually used, since the COFF assembler rejects the
- results. No one knows why it rejects them. */
-
- static void
- sdbout_field_types (type)
- tree type;
- {
- tree tail;
- for (tail = TYPE_FIELDS (type); tail; tail = TREE_CHAIN (tail))
- sdbout_one_type (TREE_TYPE (tail));
- }
-
- /* Use this to put out the top level defined record and union types
- for later reference. If this is a struct with a name, then put that
- name out. Other unnamed structs will have .xxfake labels generated so
- that they may be referred to later.
- The label will be stored in the KNOWN_TYPE_TAG slot of a type.
- It may NOT be called recursively. */
-
- static void
- sdbout_one_type (type)
- tree type;
- {
- text_section ();
-
- switch (TREE_CODE (type))
- {
- case RECORD_TYPE:
- case UNION_TYPE:
- case ENUMERAL_TYPE:
- type = TYPE_MAIN_VARIANT (type);
- /* Don't output a type twice. */
- if (TREE_ASM_WRITTEN (type))
- return;
-
- TREE_ASM_WRITTEN (type) = 1;
- #if 0 /* This change, which ought to make better output,
- makes the COFF assembler unhappy. */
- /* Before really doing anything, output types we want to refer to. */
- if (TREE_CODE (type) != ENUMERAL_TYPE)
- sdbout_field_types (type);
- #endif
-
- sdbout_record_type_name (type);
-
- /* Output a structure type. */
- {
- int size = int_size_in_bytes (type);
- int member_scl;
- tree tem;
-
- PUT_SDB_DEF (KNOWN_TYPE_TAG (type));
-
- switch (TREE_CODE (type))
- {
- case UNION_TYPE:
- PUT_SDB_SCL (C_UNTAG);
- PUT_SDB_TYPE (T_UNION);
- member_scl = C_MOU;
- break;
-
- case RECORD_TYPE:
- PUT_SDB_SCL (C_STRTAG);
- PUT_SDB_TYPE (T_STRUCT);
- member_scl = C_MOS;
- break;
-
- case ENUMERAL_TYPE:
- PUT_SDB_SCL (C_ENTAG);
- PUT_SDB_TYPE (T_ENUM);
- member_scl = C_MOE;
- break;
- }
-
- PUT_SDB_SIZE (size);
- PUT_SDB_ENDEF;
-
- /* output the individual fields */
-
- if (TREE_CODE (type) == ENUMERAL_TYPE)
- for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
- {
- PUT_SDB_DEF (IDENTIFIER_POINTER (TREE_PURPOSE (tem)));
- PUT_SDB_INT_VAL (TREE_INT_CST_LOW (TREE_VALUE (tem)));
- PUT_SDB_SCL (C_MOE);
- PUT_SDB_TYPE (T_MOE);
- PUT_SDB_ENDEF;
- }
-
- else /* record or union type */
- for (tem = TYPE_FIELDS (type); tem; tem = TREE_CHAIN (tem))
- /* Output the name, type, position (in bits), size (in bits)
- of each field. */
- /* Omit here the nameless fields that are used to skip bits. */
- if (DECL_NAME (tem) != 0)
- {
- CONTIN;
- PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (tem)));
- if (TREE_PACKED (tem))
- {
- PUT_SDB_INT_VAL (DECL_OFFSET (tem));
- PUT_SDB_SCL (C_FIELD);
- sdbout_type (TREE_TYPE (tem));
- PUT_SDB_SIZE (TREE_INT_CST_LOW (DECL_SIZE (tem))
- * DECL_SIZE_UNIT (tem));
- }
- else
- {
- PUT_SDB_INT_VAL (DECL_OFFSET (tem) / BITS_PER_UNIT);
- PUT_SDB_SCL (member_scl);
- sdbout_type (TREE_TYPE (tem));
- }
- PUT_SDB_ENDEF;
- }
- /* output end of a structure,union, or enumeral definition */
-
- PUT_SDB_PLAIN_DEF ("eos");
- PUT_SDB_INT_VAL (size);
- PUT_SDB_SCL (C_EOS);
- PUT_SDB_TAG (KNOWN_TYPE_TAG (type));
- PUT_SDB_SIZE (size);
- PUT_SDB_ENDEF;
- break;
- }
- }
- }
-
- /* Output definitions of all parameters, referring when possible to the
- place where the parameters were passed rather than the copies used
- within the function. This is done as part of starting the function.
- PARMS is a chain of PARM_DECL nodes. */
-
- static void
- sdbout_parms (parms1)
- tree parms1;
- {
- tree type;
- tree parms;
-
- for (parms = parms1; parms; parms = TREE_CHAIN (parms))
- {
- int current_sym_value = DECL_OFFSET (parms) / BITS_PER_UNIT;
-
- if (DECL_NAME (parms))
- PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (parms)));
- else
- PUT_SDB_DEF (gen_fake_label ());
-
- if (GET_CODE (DECL_RTL (parms)) == REG
- && REGNO (DECL_RTL (parms)) >= 0
- && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER)
- type = DECL_ARG_TYPE (parms);
- else
- {
- /* This is the case where the parm is passed as an int or double
- and it is converted to a char, short or float and stored back
- in the parmlist. In this case, describe the parm
- with the variable's declared type, and adjust the address
- if the least significant bytes (which we are using) are not
- the first ones. */
- #ifdef BYTES_BIG_ENDIAN
- if (TREE_TYPE (parms) != DECL_ARG_TYPE (parms))
- current_sym_value +=
- (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms)))
- - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms))));
- #endif
- if (GET_CODE (DECL_RTL (parms)) == MEM
- && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS
- && GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT
- && (INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1))
- == current_sym_value))
- type = TREE_TYPE (parms);
- else
- {
- current_sym_value = DECL_OFFSET (parms) / BITS_PER_UNIT;
- type = DECL_ARG_TYPE (parms);
- }
- }
-
- PUT_SDB_INT_VAL (current_sym_value);
- PUT_SDB_SCL (C_ARG);
- PUT_SDB_TYPE (plain_type (type));
- PUT_SDB_ENDEF;
- }
- }
-
- /* Output definitions, referring to registers,
- of all the parms in PARMS which are stored in registers during the function.
- PARMS is a chain of PARM_DECL nodes.
- This is done as part of starting the function. */
-
- static void
- sdbout_reg_parms (parms)
- tree parms;
- {
- while (parms)
- {
- if (GET_CODE (DECL_RTL (parms)) == REG
- && REGNO (DECL_RTL (parms)) >= 0
- && REGNO (DECL_RTL (parms)) < FIRST_PSEUDO_REGISTER)
- {
- PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (parms)));
- PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (DECL_RTL (parms))));
- PUT_SDB_SCL (C_REG);
- PUT_SDB_TYPE (plain_type (TREE_TYPE (parms), 0));
- PUT_SDB_ENDEF;
- }
- else if (GET_CODE (DECL_RTL (parms)) == MEM
- && GET_CODE (XEXP (DECL_RTL (parms), 0)) == PLUS
- && GET_CODE (XEXP (XEXP (DECL_RTL (parms), 0), 1)) == CONST_INT)
- {
- int offset = DECL_OFFSET (parms) / BITS_PER_UNIT;
- /* A parm declared char is really passed as an int,
- so it occupies the least significant bytes.
- On a big-endian machine those are not the low-numbered ones. */
- #ifdef BYTES_BIG_ENDIAN
- if (TREE_TYPE (parms) != DECL_ARG_TYPE (parms))
- offset += (GET_MODE_SIZE (TYPE_MODE (DECL_ARG_TYPE (parms)))
- - GET_MODE_SIZE (GET_MODE (DECL_RTL (parms))));
- #endif
- if (INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)) != offset)
- {
- PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (parms)));
- PUT_SDB_INT_VAL (INTVAL (XEXP (XEXP (DECL_RTL (parms), 0), 1)));
- PUT_SDB_SCL (C_AUTO);
- PUT_SDB_TYPE (plain_type (TREE_TYPE (parms)));
- PUT_SDB_ENDEF;
- }
- }
- parms = TREE_CHAIN (parms);
- }
- }
-
- /* Describe the beginning of an internal block within a function.
- Also output descriptions of variables defined in this block.
-
- N is the number of the block, by order of beginning, counting from 1,
- and not counting the outermost (function top-level) block.
- The blocks match the LET_STMTS in DECL_INITIAL (current_function_decl),
- if the count starts at 0 for the outermost one. */
-
- void
- sdbout_begin_block (file, line, n)
- FILE *file;
- int line;
- int n;
- {
- tree decl = current_function_decl;
- MAKE_LINE_SAFE (line);
- PUT_SDB_BLOCK_START (line - sdb_begin_function_line);
- if (n == 1)
- {
- /* Include the outermost LET_STMT's variables in block 1. */
- next_block_number = 0;
- do_block = 0;
- sdbout_block (DECL_INITIAL (decl), DECL_ARGUMENTS (decl));
- }
- next_block_number = 0;
- do_block = n;
- sdbout_block (DECL_INITIAL (decl), DECL_ARGUMENTS (decl));
- }
-
- /* Describe the end line-number of an internal block within a function. */
-
- void
- sdbout_end_block (file, line)
- FILE *file;
- int line;
- {
- MAKE_LINE_SAFE (line);
- PUT_SDB_BLOCK_END (line - sdb_begin_function_line);
- }
-
- /* Output sdb info for the current function name.
- Called from assemble_function. */
-
- void
- sdbout_mark_begin_function ()
- {
- sdbout_symbol (current_function_decl, 0);
- }
-
- /* Called at beginning of function body (after prologue).
- Record the function's starting line number, so we can output
- relative line numbers for the other lines.
- Describe beginning of outermost block.
- Also describe the parameter list. */
-
- void
- sdbout_begin_function (line)
- int line;
- {
- sdb_begin_function_line = line - 1;
- PUT_SDB_FUNCTION_START (line);
- sdbout_parms (DECL_ARGUMENTS (current_function_decl));
- sdbout_reg_parms (DECL_ARGUMENTS (current_function_decl));
- }
-
- /* Called at end of function (before epilogue).
- Describe end of outermost block. */
-
- void
- sdbout_end_function (line)
- int line;
- {
- MAKE_LINE_SAFE (line);
- PUT_SDB_FUNCTION_END (line - sdb_begin_function_line);
-
- /* Indicate we are between functions, for line-number output. */
- sdb_begin_function_line = 0;
- }
-
- /* Output sdb info for the absolute end of a function.
- Called after the epilogue is output. */
-
- void
- sdbout_end_epilogue ()
- {
- char *name = IDENTIFIER_POINTER (DECL_NAME (current_function_decl));
- PUT_SDB_EPILOGUE_END (name);
- }
-
- #endif /* SDB_DEBUGGING_INFO */
-